package com.quectel.taskserver.job.room;

import cn.hutool.core.lang.func.LambdaUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.quectel.constant.core.room.GroupRentingRoomConstants;
import com.quectel.constant.core.room.VillageRoomSuspicionOrderConstants;
import com.quectel.core.module.household.dto.HouseholdDto;
import com.quectel.core.module.household.dto.HouseholdRoomDto;
import com.quectel.core.module.household.service.HouseholdRoomService;
import com.quectel.core.module.room.dto.VillageRoomInspectionHistoryDto;
import com.quectel.core.module.room.dto.VillageRoomSuspicionOrderDto;
import com.quectel.core.module.room.dto.custom.SuspicionHouseholdSnapshotDto;
import com.quectel.core.module.room.dto.custom.SuspicionRoomInfoDto;
import com.quectel.core.module.room.service.VillageRoomInspectionHistoryService;
import com.quectel.core.module.room.service.VillageRoomSuspicionOrderService;
import com.quectel.core.module.village.dto.VillageDto;
import com.quectel.core.module.village.dto.VillageRoomDto;
import com.quectel.core.module.village.service.VillageRoomService;
import com.quectel.core.module.village.service.VillageService;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.kit.PageFetchKit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.shardingsphere.elasticjob.api.ShardingContext;
import org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author rananxin
 * @email ryan.ran@quectel.com
 * @date 2022/1/10 5:17 下午
 */
@Component
@Slf4j
public class RoomGroupRentingCheckTask implements SimpleJob {

    @DubboReference
    private VillageService villageService;
    @DubboReference
    private VillageRoomSuspicionOrderService villageRoomSuspicionOrderService;
    @DubboReference
    private VillageRoomInspectionHistoryService villageRoomInspectionHistoryService;
    @DubboReference
    private HouseholdRoomService householdRoomService;
    @DubboReference
    private VillageRoomService villageRoomService;

    @Override
    public void execute(ShardingContext shardingContext) {
        Map<String, Object> params = new HashMap<>();
        List<VillageDto> villageDtos =
                villageService.queryList(params);
        villageDtos.forEach(this::check);
    }

    /**
     * 检测群租房屋
     * @param villageDto
     */
    private void check(VillageDto villageDto) {
        final Long villageId = villageDto.getId();

        List<SuspicionRoomInfoDto> suspicionRoomInfoDtos = villageRoomSuspicionOrderService
                .querySuspicionInfo(villageId);
        log.info("小区 {} 检测出 {} 个群租可疑房间", villageDto.getName(), suspicionRoomInfoDtos.size());

        // 当前小区已经被标记为群租房的
        List<VillageRoomDto> villageRoomDtos = queryGroupRentingRoom(villageId);
        remove(villageRoomDtos, suspicionRoomInfoDtos.stream().map(SuspicionRoomInfoDto::getRoomId).collect(Collectors.toList()));

        if (CollectionUtils.isNotEmpty(suspicionRoomInfoDtos)) {
            for (SuspicionRoomInfoDto suspicionRoomInfoDto : suspicionRoomInfoDtos) {
                try {
                    List<HouseholdRoomDto> householdRoomDtos = householdRoomService.selectByRoomId(suspicionRoomInfoDto.getRoomId());
                    Long[] curIds = householdRoomDtos.stream().map(HouseholdRoomDto::getHouseholdId).toArray(Long[]::new);

                    VillageRoomInspectionHistoryDto villageRoomInspectionHistoryDto = villageRoomInspectionHistoryService
                            .selectByRoomId(suspicionRoomInfoDto.getRoomId());
                    if (villageRoomInspectionHistoryDto != null) {
                        String householdIds = villageRoomInspectionHistoryDto.getHouseholdIds();

                        VillageRoomInspectionHistoryDto updateInspectionHistoryDto = new VillageRoomInspectionHistoryDto();
                        updateInspectionHistoryDto.setId(villageRoomInspectionHistoryDto.getId());
                        updateInspectionHistoryDto.setHouseholdIds(JacksonUtils.toJsonString(curIds));
                        updateInspectionHistoryDto.setInspectionTime(new Date());
                        villageRoomInspectionHistoryService.updateById(updateInspectionHistoryDto);

                        // 检测过，留存过数据，看看人员是否有变动
                        List<Long> longs = JacksonUtils.parseArray(householdIds, Long.class);
                        if (Boolean.FALSE.equals(isChange(longs.toArray(new Long[0]), curIds))) {
                            // 人员未变化，直接跳过了
                            continue;
                        }
                    }

                    if (villageRoomInspectionHistoryDto == null) {
                        // 没有检测过，也不可能产生了订单，现在直接产生
                        VillageRoomInspectionHistoryDto saveInspectionHistoryDto = new VillageRoomInspectionHistoryDto();
                        saveInspectionHistoryDto.setRoomId(suspicionRoomInfoDto.getRoomId());
                        saveInspectionHistoryDto.setHouseholdIds(JacksonUtils.toJsonString(curIds));
                        saveInspectionHistoryDto.setInspectionTime(new Date());
                        saveInspectionHistoryDto.setCreateTime(new Date());
                        villageRoomInspectionHistoryService.save(saveInspectionHistoryDto);

                        // 产生检测处理单
                        createOrder(villageDto, suspicionRoomInfoDto, transInfo(householdRoomDtos));
                    } else {
                        // 检测过，但是人员变了，查看是否存在未处理单，存在的话，更新一下，不存在的话，创建一个新的
                        Map<String, Object> params = new HashMap<>();
                        params.put(LambdaUtil.getFieldName(VillageRoomSuspicionOrderDto::getTenantId), villageDto.getTenantId());
                        params.put(LambdaUtil.getFieldName(VillageRoomSuspicionOrderDto::getVillageId), villageId);
                        params.put(LambdaUtil.getFieldName(VillageRoomSuspicionOrderDto::getRoomId), suspicionRoomInfoDto.getRoomId());
                        params.put(LambdaUtil.getFieldName(VillageRoomSuspicionOrderDto::getHandleStatus), VillageRoomSuspicionOrderConstants.HandleStatusEnum.UNTREATED.getStatus());
                        List<VillageRoomSuspicionOrderDto> villageRoomSuspicionOrderDtos = villageRoomSuspicionOrderService.queryList(params);
                        // 再过滤确认下
                        Optional<VillageRoomSuspicionOrderDto> first = villageRoomSuspicionOrderDtos.stream()
                                .filter(o -> VillageRoomSuspicionOrderConstants.HandleStatusEnum.UNTREATED.getStatus()
                                        .equals(o.getHandleStatus()))
                                .findFirst();
                        if (first.isPresent()) {
                            // 存在未处理的，更新下，就不产生新的了，产生新的没意义
                            VillageRoomSuspicionOrderDto villageRoomSuspicionOrderDto = first.get();
                            VillageRoomSuspicionOrderDto updateDto = new VillageRoomSuspicionOrderDto();
                            updateDto.setId(villageRoomSuspicionOrderDto.getId());
                            updateDto.setPersonSnapshot(JacksonUtils.toJsonString(transInfo(householdRoomDtos)));
                            updateDto.setUpdateTime(new Date());
                            villageRoomSuspicionOrderService.updateById(updateDto);
                        } else {
                            // 产生检测处理单
                            createOrder(villageDto, suspicionRoomInfoDto, transInfo(householdRoomDtos));
                        }
                    }

                } catch (Exception e) {
                    log.error("群租嫌疑房间 检测出现异常", e);
                }
            }
        }
    }

    /**
     * 移除
     * @param curGroupRentingRooms 当前的群租房列表
     * @param suspectRoomIds 嫌疑列表
     */
    private void remove(List<VillageRoomDto> curGroupRentingRooms, List<Long> suspectRoomIds) {
        // 未检测出群租嫌疑房，把当前群租房全部设为正常的
        List<VillageRoomDto> collect = curGroupRentingRooms.stream()
                .filter(o -> StringUtils.isNotBlank(o.getTags()) && !suspectRoomIds.contains(o.getId())).map(o -> {
            HashMap<String, Object> parse = JacksonUtils.parse(o.getTags(), new TypeReference<HashMap<String, Object>>() {
            });
            parse.remove(GroupRentingRoomConstants.TagsEnum.GROUP_RENTING_ROOM.getType().toString());

            VillageRoomDto updateDto = new VillageRoomDto();
            updateDto.setId(o.getId());
            updateDto.setTags(JacksonUtils.toJsonString(parse));
            return updateDto;
        }).collect(Collectors.toList());
        villageRoomService.updateBatch(collect);
    }

    /**
     * 获取当前的群租房
     * @param villageId
     * @return
     */
    private List<VillageRoomDto> queryGroupRentingRoom(Long villageId) {
        Map<String, Object> params = new HashMap<>();
        params.put(GroupRentingRoomConstants.TAG_KEYS, Collections.singletonList(GroupRentingRoomConstants.TagsEnum.GROUP_RENTING_ROOM.getType()));
        params.put(LambdaUtil.getFieldName(VillageRoomDto::getVillageId), villageId);

        return PageFetchKit.fetchAll(r -> villageRoomService.queryList(r), params);
    }

    /**
     * 检测人员变化
     * @param lastIds 上一次检测留存的人员 id 集合
     * @param curIds 这一次的人员 id 集合
     * @return true变化了 false没变化
     */
    private static boolean isChange(Long[] lastIds, Long[] curIds) {
        if (lastIds.length != curIds.length) {
            return true;
        }

        Set<Long> lastIdsSet = new HashSet<>(Arrays.asList(lastIds));
        Set<Long> curIdsSet = new HashSet<>(Arrays.asList(curIds));

        return !lastIdsSet.equals(curIdsSet);
    }

    /**
     * 创建怀疑单
     * @param villageDto
     * @param suspicionRoomInfoDto
     * @param list
     */
    private void createOrder(VillageDto villageDto, SuspicionRoomInfoDto suspicionRoomInfoDto, List<SuspicionHouseholdSnapshotDto> list) {
        VillageRoomSuspicionOrderDto villageRoomSuspicionOrderDto = new VillageRoomSuspicionOrderDto();
        villageRoomSuspicionOrderDto.setTenantId(villageDto.getTenantId());
        villageRoomSuspicionOrderDto.setVillageId(villageDto.getId());
        villageRoomSuspicionOrderDto.setBuildingId(suspicionRoomInfoDto.getBuildingId());
        villageRoomSuspicionOrderDto.setFloorId(suspicionRoomInfoDto.getFloorId());
        villageRoomSuspicionOrderDto.setRoomId(suspicionRoomInfoDto.getRoomId());
        villageRoomSuspicionOrderDto.setResourceType(VillageRoomSuspicionOrderConstants.ResourceTypeEnum.SYS.getType());
        villageRoomSuspicionOrderDto.setHandleStatus(VillageRoomSuspicionOrderConstants.HandleStatusEnum.UNTREATED.getStatus());
        villageRoomSuspicionOrderDto.setPeopleCount(suspicionRoomInfoDto.getHouseholdCount());
        villageRoomSuspicionOrderDto.setPersonSnapshot(JacksonUtils.toJsonString(list));
        villageRoomSuspicionOrderDto.setCreateTime(new Date());
        villageRoomSuspicionOrderService.save(villageRoomSuspicionOrderDto);
    }

    /**
     * 转换
     * @param list
     * @return
     */
    private List<SuspicionHouseholdSnapshotDto> transInfo(List<HouseholdRoomDto> list){
        if (list == null) {
            return Collections.emptyList();
        }
        return list.stream().map(o->{
            SuspicionHouseholdSnapshotDto suspicionHouseholdSnapshotDto = new SuspicionHouseholdSnapshotDto();
            suspicionHouseholdSnapshotDto.setType(o.getIdentityCategory());

            HouseholdDto householdDto = o.getHouseholdDto();
            if (householdDto != null) {
                suspicionHouseholdSnapshotDto.setId(householdDto.getId());
                suspicionHouseholdSnapshotDto.setName(householdDto.getName());
                suspicionHouseholdSnapshotDto.setCardNo(householdDto.getCardNo());
                suspicionHouseholdSnapshotDto.setGender(householdDto.getGender());
                suspicionHouseholdSnapshotDto.setMobile(householdDto.getMobile());
                suspicionHouseholdSnapshotDto.setFaceImg(householdDto.getFaceImg());
            }
            return suspicionHouseholdSnapshotDto;
        }).collect(Collectors.toList());
    }
}
